package com.wuyou.sso.component;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.wuyou.sso.common.contant.AuthConstants;
import com.wuyou.sso.common.entity.OauthClientDetails;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.oauth2.common.exceptions.InvalidClientException;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.client.BaseClientDetails;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Map;

/**
 * 扩展 #{@link ClientDetailsService} 支持缓存
 *
 * @author lishangbu
 * @date 2020/03/25
 */
@Service
@Slf4j
public class CacheableClientDetailsService implements ClientDetailsService {

    /**
     * OAUTH客户端详情服务
     */
//    @DubboReference(check=false)
//    private RemoteOauthClientDetailsService remoteOauthClientDetailsService;

    /**
     * 重写原生方法支持redis缓存
     *
     * @param clientId
     * @return ClientDetails
     * @throws InvalidClientException
     */
    @Override
    @Cacheable(
            value = AuthConstants.CLIENT_DETAILS_KEY,
            key = "#clientId",
            unless = "#result == null")
    public ClientDetails loadClientByClientId(String clientId) {
//        OauthClientDetails clientDetails = remoteOauthClientDetailsService.getClientDetailsByClientId(clientId);
        OauthClientDetails clientDetails = new OauthClientDetails();
        clientDetails.setId(1L);
        clientDetails.setClientId("weihuang");
        clientDetails.setResourceIds(null);
        clientDetails.setClientSecret("weihuang");
        clientDetails.setScope("server");
        clientDetails.setAuthorizedGrantTypes("password,refresh_token,authorization_code,client_credentials");
        clientDetails.setWebServerRedirectUri(null);
        clientDetails.setAuthorities(null);
        clientDetails.setAccessTokenValidity(7200000);
        clientDetails.setRefreshTokenValidity(259200000);
        clientDetails.setAdditionalInformation("{\"enc_flag\":\"1\",\"captcha_flag\":\"1\"}");
        clientDetails.setAutoApprove(false);
        if (clientDetails == null) {
            return null;
        }
        // 适配成oauth2内置类型
        return clientDetailsWrapper(clientDetails);
    }


    /**
     * 客户端类型转化 参考
     * {@link org.springframework.security.oauth2.provider.client.JdbcClientDetailsService}
     *
     * @param origin 数据库保存参数
     * @return target oauth 类型客户端参数
     */
    private ClientDetails clientDetailsWrapper(OauthClientDetails origin) {
        BaseClientDetails target = new BaseClientDetails();
        // 必选项
        target.setClientId(origin.getClientId());
        target.setClientSecret(String.format("{noop}%s", origin.getClientSecret()));

        if (StrUtil.isNotEmpty(origin.getAuthorizedGrantTypes())) {
            target.setAuthorizedGrantTypes(CollUtil.newArrayList(origin.getAuthorizedGrantTypes().split(StrUtil.COMMA)));
        }

        if (StrUtil.isNotBlank(origin.getAuthorities())) {
            target.setAuthorities(AuthorityUtils.commaSeparatedStringToAuthorityList(origin.getAuthorities()));
        }

        if (StrUtil.isNotBlank(origin.getResourceIds())) {
            target.setResourceIds(StringUtils.commaDelimitedListToSet(origin.getResourceIds()));
        }

        if (StrUtil.isNotBlank(origin.getWebServerRedirectUri())) {
            target.setRegisteredRedirectUri(StringUtils.commaDelimitedListToSet(origin.getWebServerRedirectUri()));
        }

        if (StrUtil.isNotBlank(origin.getScope())) {
            target.setScope(StringUtils.commaDelimitedListToSet(origin.getScope()));
        }

        if (origin.getAutoApprove() != null) {
            target.setAutoApproveScopes(StringUtils.commaDelimitedListToSet(String.valueOf(origin.getAutoApprove())));
        }

        if (origin.getAccessTokenValidity() != null) {
            target.setAccessTokenValiditySeconds(origin.getAccessTokenValidity());
        }

        if (origin.getRefreshTokenValidity() != null) {
            target.setRefreshTokenValiditySeconds(origin.getRefreshTokenValidity());
        }

        String json = origin.getAdditionalInformation();
        if (StrUtil.isNotBlank(json)) {
            try {
                @SuppressWarnings("unchecked")
                Map<String, Object> additionalInformation = JSONUtil.toBean(json, Map.class);
                target.setAdditionalInformation(additionalInformation);
            } catch (Exception e) {
                log.warn("Could not decode JSON for additional information: " + json, e);
            }
        }

        return target;
    }
}
